-- fulladd_sub.vhd
-- 100910 Mathias Lundell
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;

ENTITY fulladd_sub IS
    GENERIC ( WIDTH : NATURAL := 4 );
    PORT ( a        : IN  STD_LOGIC_VECTOR( WIDTH-1 DOWNTO 0 );
           b        : IN  STD_LOGIC_VECTOR( WIDTH-1 DOWNTO 0 );
           saturate : IN  STD_LOGIC;
           add      : IN  STD_LOGIC;
           
           s        : OUT STD_LOGIC_VECTOR( WIDTH-1 DOWNTO 0 );
           overflow : OUT STD_LOGIC );   
END ENTITY fulladd_sub;

ARCHITECTURE fulladd_sub_arch OF fulladd_sub IS
    -- Adder of 2 bits
    COMPONENT add2b
        PORT ( a    : IN  STD_LOGIC;
               b    : IN  STD_LOGIC;
               cin  : IN  STD_LOGIC;
               
               s    : OUT STD_LOGIC;
               cout : OUT STD_LOGIC );
    END COMPONENT;
    
    -- Internal "buffer" signals
    SIGNAL n_cout : STD_LOGIC_VECTOR( WIDTH   DOWNTO 0 );
    SIGNAL n_s    : STD_LOGIC_VECTOR( WIDTH-1 DOWNTO 0 );
    SIGNAL n_b    : STD_LOGIC_VECTOR( WIDTH-1 DOWNTO 0 );
    SIGNAL n_ovf  : STD_LOGIC;
    
    -- Constant zeroes and ones
    CONSTANT c_zeroes : STD_LOGIC_VECTOR( WIDTH-1 DOWNTO 0 ) := (OTHERS => '0');
    CONSTANT c_ones   : STD_LOGIC_VECTOR( WIDTH-1 DOWNTO 0 ) := (OTHERS => '1');
BEGIN       
    -- Generate the full adder
    n_cout(0) <= NOT add;
    
    n_b <= NOT b WHEN add = '0' ELSE
           b;
           
    FA_generate: FOR i IN 0 TO WIDTH-1 GENERATE
        FA_i: add2b PORT MAP ( a(i), n_b(i), n_cout(i), n_s(i), n_cout(i+1) );
    END GENERATE;
    
    
    n_ovf <= n_cout(WIDTH) XOR n_cout(WIDTH-1);
    overflow <= n_ovf;
    
    -- Sum saturated when overflow = 1 else n_s
    s <= '0' &   c_ones( WIDTH-2 DOWNTO 0 ) WHEN 
            (saturate = '1' AND n_ovf = '1' AND a(WIDTH-1) = '0') ELSE
         '1' & c_zeroes( WIDTH-2 DOWNTO 0 ) WHEN 
            (saturate = '1' AND n_ovf = '1' AND a(WIDTH-1) = '1') ELSE
         n_s;
         
END ARCHITECTURE fulladd_sub_arch;

